<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>cannon.js - convex demo</title>
    <link rel="stylesheet" href="css/style.css" type="text/css" />
    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0" />
  </head>
  <body>
    <script type="module">
      import * as CANNON from '../dist/cannon-es.js'
      import { Demo } from './js/Demo.js'

      /**
       * Experiment for testing ConvexPolyhedrons.
       */

      const demo = new Demo()

      function createTetra() {
        const vertices = [
          new CANNON.Vec3(0, 0, 0),
          new CANNON.Vec3(2, 0, 0),
          new CANNON.Vec3(0, 2, 0),
          new CANNON.Vec3(0, 0, 2),
        ]
        const offset = -0.35
        for (let i = 0; i < vertices.length; i++) {
          const v = vertices[i]
          v.x += offset
          v.y += offset
          v.z += offset
        }
        return new CANNON.ConvexPolyhedron({
          vertices: vertices,
          faces: [
            [0, 3, 2], // -x
            [0, 1, 3], // -y
            [0, 2, 1], // -z
            [1, 2, 3], // +xyz
          ],
        })
      }

      function createBoxPolyhedron(size = 1) {
        const box = new CANNON.Box(new CANNON.Vec3(size, size, size))
        return box.convexPolyhedronRepresentation
      }

      // Various shapes
      demo.addScene('Various', () => {
        const world = setupWorld(demo)

        const size = 0.5
        const mass = 10

        // ConvexPolyhedron box shape
        const convexShape = createBoxPolyhedron(size)
        const boxbody = new CANNON.Body({ mass })
        boxbody.addShape(convexShape)
        boxbody.position.set(-1, size + 1, 0)
        world.addBody(boxbody)
        demo.addVisual(boxbody)

        // ConvexPolyhedron tetra shape
        const tetraShape = createTetra()
        const tetraBody = new CANNON.Body({ mass })
        tetraBody.addShape(tetraShape)
        tetraBody.position.set(-5, size + 1, -3)
        world.addBody(tetraBody)
        demo.addVisual(tetraBody)

        // The Cylinder is a ConvexPolyhedron under the hood
        const height = 2
        const radius = 0.5
        const detail = 20

        const cylinderShape = new CANNON.Cylinder(radius, radius, height, detail)
        const cylinderBody = new CANNON.Body({ mass })
        cylinderBody.addShape(cylinderShape)
        cylinderBody.position.set(0, size * 4 + 1, 0)
        cylinderBody.quaternion.setFromEuler(0, 0, Math.PI / 3)
        world.addBody(cylinderBody)
        demo.addVisual(cylinderBody)
      })

      // Box on box tilting over
      demo.addScene('Convex on convex', () => {
        const world = setupWorld(demo)

        const size = 2
        const mass = 10

        const convexShape = createBoxPolyhedron(size)

        // ConvexPolyhedron box shape
        const boxBody1 = new CANNON.Body({ mass })
        boxBody1.addShape(convexShape)
        boxBody1.position.set(0, size + 1, 0)
        world.addBody(boxBody1)
        demo.addVisual(boxBody1)

        const boxBody2 = new CANNON.Body({ mass })
        boxBody2.addShape(convexShape)
        boxBody2.position.set(-1.5, size * 4 + 1, 0)
        world.addBody(boxBody2)
        demo.addVisual(boxBody2)
      })

      // Pile of boxes
      demo.addScene('Convex wall', () => {
        const world = setupWorld(demo)

        const size = 1
        const mass = 10

        // ConvexPolyhedron box shape
        const convexShape = createBoxPolyhedron(size)
        for (let i = 0; i < 3; i++) {
          for (let j = 0; j < 3; j++) {
            const boxbody = new CANNON.Body({ mass })
            boxbody.addShape(convexShape)
            boxbody.position.set(-(size * 2 * i + 0.01), size * 2 * j + size * 1.2, 0)
            world.addBody(boxbody)
            demo.addVisual(boxbody)
          }
        }
      })

      function setupWorld(demo) {
        const world = demo.getWorld()
        world.gravity.set(0, -30, 0)

        // Tweak contact properties.
        // Contact stiffness - use to make softer/harder contacts
        world.defaultContactMaterial.contactEquationStiffness = 5e6

        // Stabilization time in number of timesteps
        world.defaultContactMaterial.contactEquationRelaxation = 3

        // Static ground plane
        const groundShape = new CANNON.Plane()
        const groundBody = new CANNON.Body({ mass: 0 })
        groundBody.addShape(groundShape)
        groundBody.quaternion.setFromEuler(-Math.PI / 2, 0, 0)
        // groundBody.position.set(-10, 0, 0)
        world.addBody(groundBody)
        demo.addVisual(groundBody)

        return world
      }

      demo.start()
    </script>
  </body>
</html>
